package com.dsg.common.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.*;
import java.util.Iterator;

/**
 * @author
 * @version 创建时间：2017年4月27日 下午10:12:17
 * @description：图片通用处理工具类
 */
public class ImageUtils {

    private static Logger logger = LoggerFactory.getLogger(ImageUtils.class);

    /**
     * 获取图片的宽
     *
     * @param srcImageFile 源图片路径
     * @return
     */
    public static int getImageWidth(String srcImageFile) {
        try {
            File file = new File(srcImageFile);
            Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("jpg");
            ImageReader reader = (ImageReader) readers.next();
            ImageInputStream iis = ImageIO.createImageInputStream(file);
            reader.setInput(iis, true);
            return reader.getWidth(0);
        } catch (IOException e) {
            e.printStackTrace();
            return 0;
        }
    }

    /***
     * 获取图片的高
     * @param srcImageFile 源图片路径
     * @return
     * @date 2016-3-30下午9:02:19
     */
    public static int getImageHeight(String srcImageFile) {
        File file = new File(srcImageFile);
        try {
            Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("jpg");
            ImageReader reader = (ImageReader) readers.next();
            ImageInputStream iis = ImageIO.createImageInputStream(file);
            reader.setInput(iis, true);

            return reader.getHeight(0);
        } catch (IOException e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 图片旋转指定角度
     *
     * @param src   文件流:源图像地址
     * @param angel 旋转度
     * @return
     */
    public static BufferedImage Rotate(Image src, int angel) {
        int src_width = src.getWidth(null);   // 源图宽度
        int src_height = src.getHeight(null);   // 源图高度
        angel = angel > 0 ? angel : (360 + angel);
        Rectangle rect_des = CalcRotatedSize(new Rectangle(new Dimension(
                src_width, src_height)), angel);

        BufferedImage res = null;
        res = new BufferedImage(rect_des.width, rect_des.height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = res.createGraphics();
        g2.setPaint(Color.WHITE);
        g2.fillRect(0, 0, rect_des.width, rect_des.height);
        // transform
        g2.translate((rect_des.width - src_width) / 2,
                (rect_des.height - src_height) / 2);
        g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);

        g2.drawImage(src, null, null);
        return res;
    }

    public static Rectangle CalcRotatedSize(Rectangle src, int angel) {
        // if angel is greater than 90 degree, we need to do some conversion
        if (angel >= 90) {
            if (angel / 90 % 2 == 1) {
                int temp = src.height;
                src.height = src.width;
                src.width = temp;
            }
            angel = angel % 90;
        }
        double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;
        double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
        double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2;
        double angel_dalta_width = Math.atan((double) src.height / src.width);
        double angel_dalta_height = Math.atan((double) src.width / src.height);

        int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha
                - angel_dalta_width));
        int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha
                - angel_dalta_height));
        int des_width = src.width + len_dalta_width * 2;
        int des_height = src.height + len_dalta_height * 2;
        return new Rectangle(new Dimension(des_width, des_height));
    }

    /***
     * 剪裁图片
     * @param srcImageFile
     * @param dest
     * @param x  起点横坐标
     * @param y  纵坐标
     * @param w  长
     * @param h  高
     * @throws IOException
     * @date 2016-3-30下午12:19:10
     */
    public static boolean cutImage(InputStream srcImageFile, File dest, int x, int y, int w, int h) {
        try {
            BufferedImage src = ImageIO.read(srcImageFile); // 读入文件
            Iterator<ImageReader> iterator = ImageIO.getImageReadersByFormatName("jpg");
            ImageReader reader = (ImageReader) iterator.next();

            //获取图片流
            ByteArrayOutputStream bs = new ByteArrayOutputStream();
            ImageOutputStream ios = ImageIO.createImageOutputStream(bs);
            ImageIO.write(src, "jpg", ios);
            InputStream in = new ByteArrayInputStream(bs.toByteArray());
            ImageInputStream iis = ImageIO.createImageInputStream(in);
            reader.setInput(iis, true);
            ImageReadParam param = reader.getDefaultReadParam();
            x = (x > 0 ? x : 0);
            y = (y > 0 ? y : 0);
            Rectangle rect = new Rectangle(x, y, w, h);
            param.setSourceRegion(rect);
            BufferedImage bi = reader.read(0, param);
            ImageIO.write(bi, "jpg", dest);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 剪裁图片(x,y,w,h,r)
     *
     * @param srcImageFile 文件流:源图像地址
     * @param dest         新图像
     * @param x            目标切片起点x坐标
     * @param y            目标切片起点y坐标
     * @param w            目标切片宽度
     * @param h            目标切片高度
     * @param r            目标切片旋转度
     * @return
     */
    public static boolean cutAndRotateImage(InputStream srcImageFile, File dest, int x, int y, int w, int h, int r) {
        try {
            /*
			 * BufferedImage是Image的一个子类，BufferedImage生成的图片在内存里有一个图像缓冲区，
			 * 利用这个缓冲区我们可以很方便的操作这个图片，通常用来做图片修改操作如大小变换、图片变灰、设置图片透明或不透明等。
			 */
            BufferedImage src = ImageIO.read(srcImageFile); // 读入文件

            //图片旋转指定角度
            BufferedImage tag = Rotate(src, r);

            //读取图片文件
            Iterator<ImageReader> iterator = ImageIO.getImageReadersByFormatName("jpg");
            ImageReader reader = (ImageReader) iterator.next();

            //获取图片流
            ByteArrayOutputStream bs = new ByteArrayOutputStream();
            ImageOutputStream ios = ImageIO.createImageOutputStream(bs);
            ImageIO.write(tag, "jpg", ios);
            InputStream in = new ByteArrayInputStream(bs.toByteArray());
            ImageInputStream iis = ImageIO.createImageInputStream(in);
            reader.setInput(iis, true);
            ImageReadParam param = reader.getDefaultReadParam();
            x = (x > 0 ? x : 0);
            y = (y > 0 ? y : 0);

            //定义一个矩形
            Rectangle rect = new Rectangle(x, y, w, h);

            //提供一个 BufferedImage，将其用作解码像素数据的目标。
            param.setSourceRegion(rect);
            BufferedImage bi = reader.read(0, param);

            //保存新图片
            ImageIO.write(bi, "jpg", dest);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /***
     * 按照比例缩放
     * @param srcImageFile
     * @param result
     * @param scale 缩放比例
     * @param flag 缩放选择:true 放大; false 缩小;
     * @return
     * @date 2016-3-30下午2:39:44
     */
    public static boolean scale(String srcImageFile, String result, int scale, boolean flag) {
        try {
            File file = new File(srcImageFile);
            BufferedImage src = ImageIO.read(file); // 读入文件
            Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("jpg");
            ImageReader reader = (ImageReader) readers.next();
            ImageInputStream iis = ImageIO.createImageInputStream(file);
            reader.setInput(iis, true);
            int width = reader.getWidth(0); // 得到源图宽
            int height = reader.getHeight(0); // 得到源图长
            if (flag) {// 放大
                width = width * scale;
                height = height * scale;
            } else {// 缩小
                width = width / scale;
                height = height / scale;
            }
            Image image = src.getScaledInstance(width, height,
                    Image.SCALE_DEFAULT);
            BufferedImage tag = new BufferedImage(width, height,
                    BufferedImage.TYPE_INT_RGB);
            Graphics g = tag.getGraphics();
            g.drawImage(image, 0, 0, null); // 绘制缩小后的图
            g.dispose();
            ImageIO.write(tag, "jpg", new File(result));// 输出到文件流
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /***
     * 缩放图像，按照长宽缩放
     * @param srcImageFile
     * @param result
     * @param height  变换后的高度
     * @param width   变换后的长度
     * @param bb      比例不对称时，是否补白，true 补白;false 不补白
     * @return
     * @date 2016-3-30下午2:44:37
     */
    public static boolean scale2(String srcImageFile, String result, int height, int width, boolean bb) {
        try {

            double ratio = 0.0; // 缩放比例
            File file = new File(srcImageFile);
            BufferedImage bi = ImageIO.read(file); // 读入文件
            Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("jpg");
            ImageReader reader = (ImageReader) readers.next();
            ImageInputStream iis = ImageIO.createImageInputStream(file);
            reader.setInput(iis, true);
            int width1 = reader.getWidth(0); // 得到源图宽
            int height1 = reader.getHeight(0); // 得到源图长
            @SuppressWarnings("static-access")
            Image itemp = bi.getScaledInstance(width, height, Image.SCALE_SMOOTH);
            // 计算比例
            if ((height1 > height) || (width1 > width)) {
                if (height1 > width1) {
                    ratio = (new Integer(height)).doubleValue()
                            / height1;
                } else {
                    ratio = (new Integer(width)).doubleValue() / width1;
                }
                AffineTransformOp op = new AffineTransformOp(AffineTransform
                        .getScaleInstance(ratio, ratio), null);
                itemp = op.filter(bi, null);
            }
            if (bb) {//补白
                BufferedImage image = new BufferedImage(width, height,
                        BufferedImage.TYPE_INT_RGB);
                Graphics2D g = image.createGraphics();
                g.setColor(Color.white);
                g.fillRect(0, 0, width, height);
                if (width == itemp.getWidth(null)) {
                    g.drawImage(itemp, 0, (height - itemp.getHeight(null)) / 2,
                            itemp.getWidth(null), itemp.getHeight(null),
                            Color.white, null);
                } else {
                    g.drawImage(itemp, (width - itemp.getWidth(null)) / 2, 0,
                            itemp.getWidth(null), itemp.getHeight(null),
                            Color.white, null);
                }
                g.dispose();
                itemp = image;
            }
            ImageIO.write((BufferedImage) itemp, "JPEG", new File(result));
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /***
     * 转换图像格式
     * @param srcImageFile 原图像地址
     * @param formatName   转换类型
     * @param destImageFile 转换后的地址
     * @return
     * @author
     * @date 2016-3-30下午2:49:15
     */
    public static boolean convert(String srcImageFile, String formatName, String destImageFile) {
        try {
            File f = new File(srcImageFile);
            f.canRead();
            f.canWrite();
            BufferedImage src = ImageIO.read(f);
            ImageIO.write(src, formatName, new File(destImageFile));
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 彩色转为黑白
     *
     * @param srcImageFile  源图像地址
     * @param destImageFile 目标图像地址
     */
    public final static void gray(String srcImageFile, String destImageFile) {
        try {
            BufferedImage src = ImageIO.read(new File(srcImageFile));
            ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
            ColorConvertOp op = new ColorConvertOp(cs, null);
            src = op.filter(src, null);
            ImageIO.write(src, "jpg", new File(destImageFile));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 给图片添加图片水印
     *
     * @param pressImg      水印图片
     * @param srcImageFile  源图像地址
     * @param destImageFile 目标图像地址
     * @param x             修正值。 默认在中间
     * @param y             修正值。 默认在中间
     * @param alpha         透明度：alpha 必须是范围 [0.0, 1.0] 之内（包含边界值）的一个浮点数字
     */
    public static boolean pressImage(String pressImg, String srcImageFile, String destImageFile,
                                     int x, int y, float alpha) {
        try {
            File file = new File(srcImageFile);
            BufferedImage src = ImageIO.read(file); // 读入文件
            Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("jpg");
            ImageReader reader = (ImageReader) readers.next();
            ImageInputStream iis = ImageIO.createImageInputStream(file);
            reader.setInput(iis, true);
            int width = reader.getWidth(0); // 得到源图宽
            int height = reader.getHeight(0); // 得到源图长
            BufferedImage image = new BufferedImage(width, height,
                    BufferedImage.TYPE_INT_RGB);
            Graphics2D g = image.createGraphics();
            g.drawImage(src, 0, 0, width, height, null);
            // 水印文件
            Image src_biao = ImageIO.read(new File(pressImg));
            int wideth_biao = src_biao.getWidth(null);
            int height_biao = src_biao.getHeight(null);
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
                    alpha));
            g.drawImage(src_biao, (width - wideth_biao - x),
                    (height - height_biao - y), wideth_biao, height_biao, null);
            // 水印文件结束
            g.dispose();
            ImageIO.write((BufferedImage) image, "jpg", new File(destImageFile));
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 给图片添加文字水印
     *
     * @param pressText     水印文字
     * @param srcImageFile  源图像地址
     * @param destImageFile 目标图像地址
     * @param fontName      水印的字体名称
     * @param fontStyle     水印的字体样式
     * @param color         水印的字体颜色
     * @param fontSize      水印的字体大小
     * @param x             修正值
     * @param y             修正值
     * @param alpha         透明度：alpha 必须是范围 [0.0, 1.0] 之内（包含边界值）的一个浮点数字
     */
    public static boolean pressText(String pressText,
                                    String srcImageFile, String destImageFile, String fontName,
                                    int fontStyle, Color color, int fontSize, int x,
                                    int y, float alpha) {
        try {
            File file = new File(srcImageFile);
            BufferedImage src = ImageIO.read(file); // 读入文件
            Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("jpg");
            ImageReader reader = (ImageReader) readers.next();
            ImageInputStream iis = ImageIO.createImageInputStream(file);
            reader.setInput(iis, true);
            int width = reader.getWidth(0); // 得到源图宽
            int height = reader.getHeight(0); // 得到源图长
            BufferedImage image = new BufferedImage(width, height,
                    BufferedImage.TYPE_INT_RGB);
            Graphics2D g = image.createGraphics();
            g.drawImage(src, 0, 0, width, height, null);
            g.setColor(color);
            g.setFont(new Font(fontName, fontStyle, fontSize));
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
                    alpha));
            // 在指定坐标绘制水印文字
            g.drawString(pressText, (width - (getLength(pressText) * fontSize))
                    / 2 + x, (height - fontSize) / 2 + y);
            g.dispose();
            ImageIO.write(image, "jpg", new File(destImageFile));// 输出到文件流
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 计算text的长度（一个中文算两个字符）
     *
     * @param text
     * @return
     */
    public static int getLength(String text) {
        int length = 0;
        for (int i = 0; i < text.length(); i++) {
            if (new String(text.charAt(i) + "").getBytes().length > 1) {
                length += 2;
            } else {
                length += 1;
            }
        }
        return length / 2;
    }

    /**
     * 使用ImageReader获取图片尺寸
     *
     * @param src 源图片路径
     */
    public void getImageSizeByImageReader(String src) {
        long beginTime = System.currentTimeMillis();
        File file = new File(src);
        try {
            Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("jpg");
            ImageReader reader = (ImageReader) readers.next();
            ImageInputStream iis = ImageIO.createImageInputStream(file);
            reader.setInput(iis, true);
            System.out.println("width:" + reader.getWidth(0));
            System.out.println("height:" + reader.getHeight(0));
        } catch (IOException e) {
            logger.error("ImageUtils.getImageSizeByImageReader", e);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("使用[ImageReader]获取图片尺寸耗时：[" + (endTime - beginTime) + "]ms");
    }

    /**
     * 使用BufferedImage获取图片尺寸
     *
     * @param src 源图片路径
     */
    public void getImageSizeByBufferedImage(String src) {
        long beginTime = System.currentTimeMillis();
        File file = new File(src);
        FileInputStream is = null;
        try {
            is = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            logger.error("ImageUtils.getImageSizeByImageReader", e);
        }
        BufferedImage sourceImg = null;
        try {
            sourceImg = ImageIO.read(is);
            System.out.println("width:" + sourceImg.getWidth());
            System.out.println("height:" + sourceImg.getHeight());
        } catch (IOException e1) {
            logger.error("ImageUtils.getImageSizeByImageReader", e1);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("使用[BufferedImage]获取图片尺寸耗时：[" + (endTime - beginTime) + "]ms");
    }
}
